/**
* All Rights Reserved , Copyright (C) 2021 , 青岛鼎信通讯股份有限公司
*
* SdProjectAppointmentService
* SD项目任命
*
* 修改纪录
* 2021-12-14 版本：1.0 jiangtao 创建。
* @version 版本：1.0
* @author 作者：jiangtao
* 创建日期：2021-12-14
*/
package com.topscomm.gpm.service.impl;

import com.alibaba.fastjson.JSON;
import com.sun.mail.util.MailSSLSocketFactory;
import com.topscomm.base.BaseSystemConst;
import com.topscomm.base.pojo.BaseChangeLogEntity;
import com.topscomm.base.service.impl.BaseChangeLogService;
import com.topscomm.basic.exception.BusinessException;
import com.topscomm.basic.exception.ServiceException;
import com.topscomm.cbo.pojo.*;
import com.topscomm.cbo.service.*;
import com.topscomm.gpm.pojo.*;
import com.topscomm.cbo.pojo.CboAttachmentEntity;
import com.topscomm.cbo.pojo.CboAttachmentTypeEntity;
import com.topscomm.cbo.pojo.CboUserEntity;
import com.topscomm.cbo.service.ICboAttachmentService;
import com.topscomm.cbo.service.ICboAttachmentTypeService;
import com.topscomm.cbo.service.ICboUserService;
import com.topscomm.message.mail.MailMessageEntity;
import com.topscomm.mis.constant.MisSystemConst;
import com.topscomm.mis.mobile.message.service.SendMessageService;
import com.topscomm.pub.util.*;
import com.topscomm.gpm.GpmSystemConst;
import com.topscomm.gpm.pojo.GpmProjectEntity;
import com.topscomm.gpm.pojo.GpmProjectTeamEntity;
import com.topscomm.gpm.pojo.GpmProjectTeamTypeEntity;
import com.topscomm.gpm.utils.ConvertTimeUtil;
import com.topscomm.gpm.utils.GenerateAppointmentTemplateUtil;
import com.topscomm.gpm.utils.PdfToImageUtil;
import com.topscomm.tap.TapEntity;
import com.topscomm.tap.common.FlowDatacodeCache;
import com.topscomm.tap.common.ParameterCache;
import com.topscomm.tap.common.SessionUserBean;
import com.topscomm.tap.common.TapSystemConst;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.io.ZipInputStream;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.unzip.UnzipUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.topscomm.gpm.service.IGpmProjectAppointmentService;
import com.topscomm.gpm.service.impl.auto.GpmProjectAppointmentServiceAuto;
import com.topscomm.basic.BasicEntity;
import com.topscomm.basic.util.PrimaryKeyUtil;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import java.util.Map;

@Service(value = "gpmProjectAppointmentService")
@Scope(value = "singleton")
public class GpmProjectAppointmentService extends GpmProjectAppointmentServiceAuto implements IGpmProjectAppointmentService {
	private static final Logger logger = LoggerFactory.getLogger(GpmProjectAppointmentService.class);
	FlowDatacodeCache flowDatacodeCache = new FlowDatacodeCache();
	protected List<Map<String, Object>> flowidList = new ArrayList();
	@Autowired
	private ICboAttachmentService cboAttachmentService;
	@Autowired
	private ICboAttachmentTypeService cboAttachmentTypeService;
	@Autowired
	private GpmProjectService gpmProjectService;
	@Autowired
	private GpmProjectTeamService gpmProjectTeamService;
	@Autowired
	private ICboUserService cboUserService;
	@Autowired
	private GpmProjectTeamTypeService gpmProjectTeamTypeService;
//	@Autowired
//	private ICboMessageAppService cboMessageAppService;
//	@Autowired
//	private ICboMessageSysService cboMessageSysService;
	@Autowired
	private BaseChangeLogService baseChangeLogService;
	@Autowired
	private GpmProjectUniversalChangeService gpmProjectUniversalChangeService;
	@Autowired
	private SendMessageService sendMessageService;

	private static final String INVALID_ADDRESS_MESSAGE = "Invalid Addresses";

	private static final Map<String, String> levelMap = new HashMap<>();

	static {
		levelMap.put("0", "A");
		levelMap.put("1", "B");
		levelMap.put("2", "C");
		levelMap.put("3", "D");
	}
	/**
	 * @author: jiangtao
	 * @date: 2021-12-14
	 * @param entity
	 * @throws
	 * @description:单号生成
	 * @modify:
	 */
	@Override
	protected void beforeInsert(BasicEntity entity){
		super.beforeInsert(entity);
		if (entity.getId() <= 0) {// 赋值Id和单号
			long[] arrayId = PrimaryKeyUtil.GeneIDs(entity.getTableName(), 1);
			entity.setId(arrayId[0]);
			String docNo = String.valueOf(arrayId[0]);
			docNo = docNo.substring(0, 6) + docNo.substring(9);
			entity.setValue(GpmProjectAppointmentEntity.FieldDocno, docNo);
		}
		// 判断是否是第一次任命
		GpmProjectAppointmentEntity appointmentEntity = (GpmProjectAppointmentEntity) entity;
		String projectCode = appointmentEntity.getProjectcode();
		long count = this.queryTimes(projectCode);
		if (count == 1) {
			appointmentEntity.setSyspush("1");
		}
		appointmentEntity.setVersion(count);
	}

	private long queryTimes(String projectCode) {
		List<Map<String, Object>> maps = this.selectExecute(" select count(id) as count from GPMProjectAppointment where projectcode = '" + projectCode + "'");
		long count = ConvertUtil.convertToLong(maps.get(0).get("count"));
		count+=1;
		return count;
	}

	/**
	 * @Description: 生成任命书编号
	 * @Author: mengmeng
	 * @Date: 2021/8/18 17:02
	 * @Version: 1.0
	 */
	public String generateAppointNumber(String projectCode) {
		// 获取项目等级
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" {0} = '{1}' ", GpmProjectEntity.FieldProjectcode, projectCode);
		List<GpmProjectEntity> sdProjectEntities = gpmProjectService.queryByWhere(sql.toString());
		if (CollectionUtils.isEmpty(sdProjectEntities)) {
			return "";
		}
		String projectLevel = sdProjectEntities.get(0).getProjectlevel();
		//赋值任命书编号
		sql.clear();
		SimpleDateFormat sdFormat = new SimpleDateFormat("yyyyMM");
		String dateCode = sdFormat.format(new Date());
		String substring = dateCode.substring(0, 4);
		String month = dateCode.substring(4);
		String flowCode = "";
		boolean isABLevel = "0".equals(projectLevel) || "1".equals(projectLevel);
		if (isABLevel) {
			// A、B 级项目
			sql.appendSingle("select APPOINTMENTNUMBER from GPMPROJECTAPPOINTMENT a left join GpmPROJECT b on a.projectcode = b.projectcode where b.projectlevel in ({0}) and a.APPOINTMENTNUMBER like '%{1}%' order by a.CREATEON DESC ", "'0','1'", substring);
			// 按照创建日期倒序取A、B级项目的任命书编号
			List<Map<String, Object>> appointmentnumberlist = this.selectExecute(sql.toString());
			if (appointmentnumberlist.size() != 0) {
				// 取当月任命书中编号最大的编号
				String lastMaxIndex = "0";
				for (Map<String, Object> temp : appointmentnumberlist) {
					String appointmentNumber = ConvertUtil.convertToString(temp.get("appointmentnumber"));
					// AB级的项目任命书编号为12位,并且是当月的
					if (!StringUtil.isEmpty(appointmentNumber) && appointmentNumber.length() == 12 && month.equals(getMonthOfAppointmentNumber(appointmentNumber, true))) {
						//
						String indexOfAppointmentNumber = getIndexOfAppointmentNumber(appointmentNumber, true);
						lastMaxIndex = ConvertUtil.convertToInt(lastMaxIndex) < ConvertUtil.convertToInt(indexOfAppointmentNumber) ? indexOfAppointmentNumber : lastMaxIndex;
					}
				}
				if ("0".equals(lastMaxIndex)) {
					// 没有当月的数据
					flowCode = "001";
				} else {
					// 当月最大顺序号加一
					DecimalFormat decimalFormat = new DecimalFormat("000");
					int i = Integer.parseInt(lastMaxIndex) + 1;
					flowCode = decimalFormat.format(i);
				}
			} else {
				// 如果为空，则当前任命为当月生成的第一份任命书
				flowCode = "001";
			}
			flowCode = "[" + substring + "]" + month + flowCode + "号";
			return flowCode;
		} else {
			// C、D 级项目
			sql.appendSingle("select APPOINTMENTNUMBER from GPMPROJECTAPPOINTMENT a left join SDPROJECT b on a.projectcode = b.projectcode where b.projectlevel in ({0}) and a.APPOINTMENTNUMBER like '%{1}%' order by a.CREATEON DESC ", "'2','3'", substring);
			List<Map<String, Object>> appointmentnumberlist = this.selectExecute(sql.toString());
			if (appointmentnumberlist.size() != 0) {
				String lastMaxIndex = "0";
				for (Map<String, Object> temp : appointmentnumberlist) {
					String appointmentNumber = ConvertUtil.convertToString(temp.get("appointmentnumber"));
					// AB级的项目任命书编号为12位,并且是当月的
					if (!StringUtil.isEmpty(appointmentNumber) && appointmentNumber.length() == 13 && month.equals(getMonthOfAppointmentNumber(appointmentNumber, false))) {
						//
						String indexOfAppointmentNumber = getIndexOfAppointmentNumber(appointmentNumber, false);
						lastMaxIndex = ConvertUtil.convertToInt(lastMaxIndex) < ConvertUtil.convertToInt(indexOfAppointmentNumber) ? indexOfAppointmentNumber : lastMaxIndex;
					}
				}
				if ("0".equals(lastMaxIndex)) {
					flowCode = "001";
				} else {
					// 当月最大顺序号加一
					DecimalFormat decimalFormat = new DecimalFormat("000");
					int i = Integer.parseInt(lastMaxIndex) + 1;
					flowCode = decimalFormat.format(i);
				}
			} else {
				flowCode = "001";
			}
			flowCode = "[" + substring + "]" + levelMap.get(projectLevel) + month + flowCode + "号";
			return flowCode;
		}
	}

	/**
	 * @Description:    获取任命书编号的顺序号
	 * @Author:         mengmeng
	 * @Date:           2021/10/22 17:44
	 * @Version:        1.0
	 */
	private String getIndexOfAppointmentNumber(String appointmentNumber, boolean whetherABLevel) {
		if (whetherABLevel) {
			return appointmentNumber.substring(8, 11);
		}
		return appointmentNumber.substring(9, 12);
	}
	/**
	 * @Description:    获取任命书编号的月份
	 * @Author:         mengmeng
	 * @Date:           2021/10/22 17:44
	 * @Version:        1.0
	 */
	private String getMonthOfAppointmentNumber(String appointmentNumber, boolean whetherABLevel) {
		if (whetherABLevel) {
			return appointmentNumber.substring(6, 8);
		}
		return appointmentNumber.substring(7, 9);
	}

	/**
	 * @Title: beforeSubmit
	 * @description: 插入流程，更细子表数据
	 * @param entity
	 * @param sessionUserBean
	 * @author: lanjianwei
	 * @date: 2021年1月7日上午9:55:15
	 * @modify:
	 */
	@Override
	protected void beforeSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
		super.beforeSubmit(entity, sessionUserBean);
		GpmProjectAppointmentEntity gpmProjectAppointmentEntity = (GpmProjectAppointmentEntity) entity;
		this.flowidList = flowDatacodeCache.getApprovalFlowListMap("ApprovalFlow_GpmProjectAppointment",
				gpmProjectAppointmentEntity.getApplyusercode(), "sortcode");
		if (flowidList.size() > 0) {// 赋值审批流程id
			gpmProjectAppointmentEntity.setFlowid(ConvertUtil.convertToLong(flowidList.get(0).get("id")));
		} else {
			throw new ServiceException("没有匹配的审批流，请联系管理员！");
		}
		//子表行状态更新
		long id = gpmProjectAppointmentEntity.getId();
		StringBufferProxy whersql = new StringBufferProxy();
		whersql.appendLineSingle("appointmentid = '{0}'", id);
		List<GpmProjectTeamEntity> sdProjectTeamEntities = gpmProjectTeamService.queryByWhere(whersql.toString());
		for (GpmProjectTeamEntity gpmProjectTeamEntity : sdProjectTeamEntities) {
			gpmProjectTeamEntity.setState(1);
			gpmProjectTeamService.updateEntity(gpmProjectTeamEntity);
		}
		// 更新主表提醒时间，不再提醒
		String projectCode = gpmProjectAppointmentEntity.getProjectcode();
		List<GpmProjectEntity> projectList = gpmProjectService.queryByWhere(" projectcode  = '" + projectCode + "'");
		if (!CollectionUtils.isEmpty(projectList)) {
			GpmProjectEntity project = projectList.get(0);
			project.setReminddate(null);
			gpmProjectService.updateEntity(project);
		}
	}

	/**
	 * @description: 提交审批后
	 * @param entity
	 * @param sessionUserBean
	 * @return void
	 * @author: wangxinhua
	 * @date: 2021/12/16 14:15
	 * @modify:
	 */
	@Override
    protected void afterSubmit(TapEntity entity, SessionUserBean sessionUserBean) {
	    //生成变更记录
		GpmProjectAppointmentEntity gpmProjectAppointmentEntity = (GpmProjectAppointmentEntity)entity;
		if(gpmProjectAppointmentEntity.getVersion() > 1) {
			Map<String,Object> appointmentMap = gpmProjectAppointmentEntity.convertToMap();
			try {
				//删除上次的basechangelog
				baseChangeLogService.deleteByWhere(" topsourcetype='"+ gpmProjectAppointmentEntity.getTableName()+"'"
						+ " and topsourceid='"+ gpmProjectAppointmentEntity.getId()+"'"
						+ " and version="+ gpmProjectAppointmentEntity.getVersion());
				Map<String, Object> changeData = this.getBaseChangeEntity(appointmentMap);
				saveBaseChangelog(changeData, false);
			} catch (Exception e) {
				throw new ServiceException(e.getMessage());
			}
		}
        try {
            StringBufferProxy sql = new StringBufferProxy();
            sql.appendLineSingle("update CboApprovalFlowIns set ");
            sql.appendLineSingle("extendfield1 = (select docno from {0} "
                            + "where CboApprovalFlowIns.sourceid = {0}.id " + "and CboApprovalFlowIns.sourcetype = '{0}'),",
                    entity.getTableName());
            sql.appendLineSingle("extendfield2 = (select deptcode from {0} "
                            + "where CboApprovalFlowIns.sourceid = {0}.id " + "and CboApprovalFlowIns.sourcetype = '{0}'),",
                    entity.getTableName());
            sql.appendLineSingle("extendfield3 = (select usercode from {0} "
                            + "where CboApprovalFlowIns.sourceid = {0}.id " + "and CboApprovalFlowIns.sourcetype = '{0}')",
                    entity.getTableName());
            sql.appendLineSingle("where sourceid = '{0}' and sourcetype='{1}'", entity.getId(), entity.getTableName());

            this.getDao().updateExecute(sql.toString());
            this.updateUniversalChange(entity, new Date(), GpmProjectAppointmentEntity.tableName);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
		super.afterSubmit(entity, sessionUserBean);
    }
	/**
	 * @description: 保存字段变更
	 * @param changeData
	 * @return void
	 * @author: wangxinhua
	 * @date: 2021/12/10 16:11
	 * @modify:
	 */
	public void saveBaseChangelog(Map<String, Object> changeData, Boolean ignoreNoChange) {
		BasicEntity mainContent = (BasicEntity)changeData.get("mainContent");
		List<BasicEntity> teamTypeContent = (List<BasicEntity>)changeData.get("teamTypeContent");
		List<BasicEntity> teamContent = (List<BasicEntity>)changeData.get("teamContent");
        if(mainContent == null && teamTypeContent.size()<=0 && teamContent.size()<=0 && !ignoreNoChange){
            throw new ServiceException("无变更内容无法提交审批，请先更改数据！");
        }
		if(mainContent != null){
			baseChangeLogService.insert(mainContent);
		}
		baseChangeLogService.insertBatch(teamTypeContent);
		baseChangeLogService.insertBatch(teamContent);
	}

	private Map<String, Object> getBaseChangeEntity(Map<String, Object> inputMap) throws Exception {
		long projectId = ConvertUtil.convertToLong(inputMap.get("projectid"));

		// 获取之前版本主表数据
		Map<String, Object> historyData = this.queryMapByWhere(" projectid=" + projectId + " order by version desc").get(1);
		// 所有变更数据返回
		Map<String, Object> resMap = new HashMap<String, Object>();

		// 组装主表要去对比的数据
		Map<String, Object> changeMap = new HashMap<String, Object>();
		changeMap.put("topsourcetype", GpmProjectAppointmentEntity.tableName);
		changeMap.put("topsourceid", ConvertUtil.convertToString(inputMap.get("id")));
		changeMap.put("sourcetype", GpmProjectAppointmentEntity.tableName);
		changeMap.put("sourceid", ConvertUtil.convertToString(inputMap.get("id")));
		changeMap.put("newmap", inputMap);
		changeMap.put("oldmap", historyData);
		changeMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Edit);
		changeMap.put("version", ConvertUtil.convertToString(inputMap.get("version")));
		BaseChangeLogEntity mainContent = this.getMainChangeLogEntity(changeMap);
		// 获取之前版本团队类别
		List<Map<String, Object>> teamTypeHistoryList = gpmProjectTeamTypeService.queryMapByWhere(" appointmentid=" + historyData.get("id"));
		// 获取当前前版本团队类别
		List<Map<String, Object>> teamTypeList = gpmProjectTeamTypeService.queryMapByWhere(" appointmentid=" + inputMap.get("id"));

		List<BasicEntity> teamTypeContent = this.getTeamTypeChangeEntity(teamTypeList, teamTypeHistoryList, inputMap);
		// 获取之前版本团队成员
		List<Map<String, Object>> teamHistoryList = gpmProjectTeamService.queryMapByWhere(" appointmentid=" + historyData.get("id"));
		// 获取当前版本团队成员
		List<Map<String, Object>> teamList = gpmProjectTeamService.queryMapByWhere(" appointmentid=" + inputMap.get("id"));
		// 获取产品信息变更
		List<BasicEntity> teamContent = this.getTeamChangeEntity(teamList, teamHistoryList, inputMap);

		resMap.put("mainContent", mainContent);
		resMap.put("teamTypeContent", teamTypeContent);
		resMap.put("teamContent", teamContent);
		return resMap;
	}

	private List<BasicEntity> getTeamTypeChangeEntity(List<Map<String, Object>> teamTypeList, List<Map<String, Object>> teamTypeHistoryList, Map<String, Object> historyData) throws Exception {
		//所有变更的结果
		List<BasicEntity> resContent = new ArrayList<BasicEntity>();
		Map<String, Object> changeProductMap = new HashMap<String, Object>();
		changeProductMap.put("sourcetype", GpmProjectTeamTypeEntity.tableName);
		changeProductMap.put("topsourcetype", GpmProjectAppointmentEntity.tableName);
		changeProductMap.put("topsourceid", ConvertUtil.convertToString(historyData.get("id")));
		changeProductMap.put("version", ConvertUtil.convertToString(historyData.get("version")));
		List<String> noDelIds = new ArrayList<String>();
		for (Map<String, Object> newItem : teamTypeList) {
			if (newItem.containsKey("copysourceid") && !"0".equals(newItem.get("copysourceid").toString())) {
				boolean hasHistory = false;
				Map<String, Object> matchHistory = new HashMap<String, Object>();
				for (Map<String, Object> historyItem : teamTypeHistoryList) {
					if (newItem.get("copysourceid").toString().equals(historyItem.get("id").toString())) {
						hasHistory = true;
						matchHistory = historyItem;
					}
				}
				if (hasHistory) {
					noDelIds.add(ConvertUtil.convertToString(matchHistory.get("id")));
					changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Edit);
					changeProductMap.put("newmap", newItem);
					changeProductMap.put("oldmap", matchHistory);
					changeProductMap.put("sourceid", newItem.get("id"));
					BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
					if(perContent != null){
						resContent.add(perContent);
					}
				}
			} else {
				changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Add);
				changeProductMap.put("newmap", newItem);
				changeProductMap.put("oldmap", newItem);
				changeProductMap.put("sourceid", newItem.get("id"));
				BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
				resContent.add(perContent);
			}
		}
		//查询删除的产品线
		if(noDelIds.size()>0){
			List<Map<String,Object>> delProducts = gpmProjectTeamTypeService.queryMapByWhere( " appointmentid =" + teamTypeHistoryList.get(0).get("appointmentid") + " and id not in (" + StringUtils.join(noDelIds, ",") + ")");
			for(Map<String,Object> delItem : delProducts){
				changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Del);
				changeProductMap.put("newmap", delItem);
				changeProductMap.put("oldmap", delItem);
				changeProductMap.put("sourceid", delItem.get("id"));
				BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
				resContent.add(perContent);
			}
		}
		return resContent;
	}

	private List<BasicEntity> getTeamChangeEntity(List<Map<String, Object>> teamList, List<Map<String, Object>> teamHistoryList, Map<String, Object> historyData) throws Exception {
		String sourceType = GpmProjectTeamEntity.tableName;
		String topsourcetype = GpmProjectAppointmentEntity.tableName;
		String topsourceid = ConvertUtil.convertToString(historyData.get("id"));
		//所有变更的结果
		List<BasicEntity> resContent = new ArrayList<BasicEntity>();
		Map<String, Object> changeProductMap = new HashMap<String, Object>();
		changeProductMap.put("sourcetype", sourceType);
		changeProductMap.put("topsourcetype",topsourcetype);
		changeProductMap.put("topsourceid", topsourceid);
		changeProductMap.put("version", ConvertUtil.convertToString(historyData.get("version")));
		List<String> noDelIds = new ArrayList<String>();
		for (Map<String, Object> newItem : teamList) {
			if (newItem.containsKey("copysourceid") && !"0".equals(newItem.get("copysourceid").toString())) {
				boolean hasHistory = false;
				Map<String, Object> matchHistory = new HashMap<String, Object>();
				for (Map<String, Object> historyItem : teamHistoryList) {
					if (newItem.get("copysourceid").toString().equals(historyItem.get("id").toString())) {
						hasHistory = true;
						matchHistory = historyItem;
					}
				}
				if (hasHistory) {
					noDelIds.add(ConvertUtil.convertToString(matchHistory.get("id")));
					changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Edit);
					changeProductMap.put("newmap", newItem);
					changeProductMap.put("oldmap", matchHistory);
					changeProductMap.put("sourceid", newItem.get("id"));
					BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
					if(perContent != null){
						resContent.add(perContent);
					}
				}
			} else {
				changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Add);
				changeProductMap.put("newmap", newItem);
				changeProductMap.put("oldmap", newItem);
				changeProductMap.put("sourceid", newItem.get("id"));
				BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
				resContent.add(perContent);
			}
		}
		//查询删除的产品线
		if(noDelIds.size()>0){
			List<Map<String,Object>> delProducts = gpmProjectTeamService.queryMapByWhere( " appointmentid =" + teamHistoryList.get(0).get("appointmentid") + " and id not in (" + StringUtils.join(noDelIds, ",") + ")");
			for(Map<String,Object> delItem : delProducts){
				changeProductMap.put("baselogoperatetype", BaseSystemConst.BaseLogOperateTypeEnum.Del);
				changeProductMap.put("newmap", delItem);
				changeProductMap.put("oldmap", delItem);
				changeProductMap.put("sourceid", delItem.get("id"));
				BaseChangeLogEntity perContent = this.getMainChangeLogEntity(changeProductMap);
				resContent.add(perContent);
			}
		}
		return resContent;
	}

	@Override
	@Transactional
	public void generateAppointment(Map<String, Object> param) throws Exception {
		String appointmentId = ConvertUtil.convertToString(param.get("appointmentid"));
		deleteAppointment(appointmentId);
		Date now = new Date();
		param.put("nowdate", new SimpleDateFormat("yyyy-MM-dd").format(now));
		param.put("nowdateup", ConvertTimeUtil.dataToUpper3(new SimpleDateFormat("yyyy-MM-dd").format(now)));
		String tempZipDirectoryName = null;
		String property = System.getProperties().getProperty("file.separator");
		String projectName = ConvertUtil.convertToString(param.get("projectname"));
		projectName = projectName.endsWith("项目") ? projectName : projectName + "项目";
		String distFileName = projectName + "任命书";
		// 删除文件名中不允许包含的字符，防止报错
		String[] split = GpmSystemConst.generateAppointmentPrevent.split(",");
		for(String str : split) {
			distFileName = distFileName.replaceAll(str, "");
		}
		try {
			// 临时目录，用于解压缩文件
			String uuid = UUID.randomUUID().toString();
			tempZipDirectoryName = BaseUtil.getProjectPath() + "zip" + property + uuid;
			File tempZipDirectory = new File(tempZipDirectoryName);
			if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
				tempZipDirectory.mkdirs();
			}
		} catch (Exception e) {
			throw new ServiceException(e);
		} finally {
			// 删除压缩文件
			FileUtil.deleteFile(tempZipDirectoryName + property + "项目任命书模板.docx");
			FileUtil.deleteFile(tempZipDirectoryName + property + distFileName + "任命书");
			// 删除临时目录
			FileUtil.deleteDirectory(tempZipDirectoryName, true);
		}
	}

	@Override protected void beforeInsertBatch(List<BasicEntity> listEntity) throws ServiceException {
		super.beforeInsertBatch(listEntity);
	}

	/**
	 * @Description:    现在任命书模板
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:58
	 * @Version:        1.0
	 */
	private void downloadTemplate(String disAddr) {
		List<CboAttachmentTypeEntity> cboAttachmentTypeEntities = cboAttachmentTypeService.queryByWhere(" sourcetype = 'GpmProjectAppointmentTemplate' ");
		if (CollectionUtils.isEmpty(cboAttachmentTypeEntities)) {
			throw new ServiceException("未配置任命书模板附件类型！！！");
		}
		CboAttachmentTypeEntity attachmentType = cboAttachmentTypeEntities.get(0);
		String property = System.getProperties().getProperty("file.separator");

		FTPProcessor ftpProcessor = null;
		try {
			// 打开FTP连接,下载并解压
			ftpProcessor = new FTPProcessor();
			ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
					Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
					attachmentType.getFtppwd());
			// Ftp文件路径
			String ftpFilePath = "1.docx";
			// Zip文件下载路径，下载Zip文件
			String tempZipFilePath = disAddr + property + "项目任命书模板.docx";
			ftpProcessor.download(ftpFilePath, tempZipFilePath);
		} catch (Exception ex) {
			throw new ServiceException(ex);
		} finally {
			if (ftpProcessor != null) {
				try {
					ftpProcessor.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

	}

	@Override
	protected void afterInsert(BasicEntity entity) throws ServiceException {
		GpmProjectAppointmentEntity appointmentEntity = (GpmProjectAppointmentEntity) entity;
		String projectCode = appointmentEntity.getProjectcode();
		long appointId = appointmentEntity.getId();
		String sysPush = appointmentEntity.getSyspush();
		long projectid = appointmentEntity.getProjectid();

		if (!StringUtil.isEmpty(sysPush) && sysPush.equals("1")) {
			// 首次任命
			//sdProjectTeamTypeService.insertTeamType(projectCode, appointId,projectid);
		} else {
			// 二次任命，复制上次的任命成员
			StringBufferProxy sql = new StringBufferProxy();
			sql.appendSingle(" projectcode = '{0}' ", projectCode);
			sql.appendSingle(" order by createon desc ");
			// 查询最近上一次的任命书
			List<GpmProjectAppointmentEntity> list = this.queryByWhere(sql.toString());
			if (CollectionUtils.isEmpty(list) || list.size() == 1) {
				// 如果为空，则应该是首次任命
				//sdProjectTeamTypeService.insertTeamType(projectCode, appointId,projectid);
				return;
			}
			GpmProjectAppointmentEntity lastAppointment = list.get(1);
			// 查询上次任命的人员和项目组类型
			List<GpmProjectTeamEntity> projectTeamDoList = gpmProjectTeamService.queryByAppointmentId(ConvertUtil.convertToString(lastAppointment.getId()));
			Map<Long, List<GpmProjectTeamEntity>> teamIdMap = projectTeamDoList.stream().collect(Collectors.groupingBy(GpmProjectTeamEntity::getTeamid));
			List<GpmProjectTeamTypeEntity> appointmentHistoryList = gpmProjectTeamTypeService.queryByAppointmentId(ConvertUtil.convertToString(lastAppointment.getId()));
			if (CollectionUtils.isEmpty(appointmentHistoryList)) {
				// 历史数据，暂不带出项目组和团队成员
				//sdProjectTeamTypeService.insertTeamType(projectCode, appointId,projectid);
				return;
			}
			// 复制上次任命的团队和名称
			List<BasicEntity> newTeamTypeList = new ArrayList<>();
			List<BasicEntity> newTeamList = new ArrayList<>();
			GpmProjectTeamEntity newTeamDo = null;
			for (GpmProjectTeamTypeEntity teamType : appointmentHistoryList) {
				GpmProjectTeamTypeEntity teamTypeDo = copyTeamTypeDo(appointId, teamType);
				newTeamTypeList.add(teamTypeDo);
				List<GpmProjectTeamEntity> teamList = teamIdMap.get(teamType.getId());
				if (CollectionUtils.isEmpty(teamList)) {
					continue;
				}
				Set<String> revokeUserCodeSet = teamList.stream().filter(item -> GpmSystemConst.Sd_TAEM_APPOINTMENTTYPE_REVOKE.equals(item.getAppointmenttype())).map(GpmProjectTeamEntity::getUsercode).collect(Collectors.toSet());
				for (GpmProjectTeamEntity teamDo : teamList) {
					if ("2".equals(teamDo.getAppointmenttype())) {
						// 撤销任命
						continue;
					}
					if (revokeUserCodeSet.contains(teamDo.getUsercode())) {
						// 该人员在该组中既有任命又有撤销
						continue;
					}
					// newTeamDo = new SdProjectTeamEntity();
					// BeanUtils.copyProperties(teamDo, newTeamDo);
					newTeamDo = teamDo;
					newTeamDo.setCopysourceid(newTeamDo.getId());
					newTeamDo.setId(0L);
					newTeamDo.setTeamid(teamTypeDo.getId());
					newTeamDo.setAppointmentid(appointId);
					newTeamDo.setCandelete(GpmSystemConst.Sd_TEAM_CAN_NOT_DELETE);
					newTeamDo.setState(0);
					newTeamList.add(newTeamDo);
				}
			}
			gpmProjectTeamTypeService.insertBatch(newTeamTypeList);
			gpmProjectTeamService.insertBatch(newTeamList);
			//变更模块数据增加
			this.insertUniversalChange(appointmentEntity);
		}
	}

	private void insertUniversalChange(GpmProjectAppointmentEntity appointmentEntity) {
		GpmProjectEntity projectEntity = gpmProjectService.queryById(ConvertUtil.convertToString(appointmentEntity.getProjectid()));
		GpmProjectUniversalChangeEntity universalChangeEntity = new GpmProjectUniversalChangeEntity();
		universalChangeEntity.setProjectname(projectEntity.getProjectname());
		universalChangeEntity.setProjectid(projectEntity.getId());
		universalChangeEntity.setProjectcode(projectEntity.getProjectcode());
		universalChangeEntity.setSourcetype(GpmProjectAppointmentEntity.tableName);
		universalChangeEntity.setSourceid(appointmentEntity.getId());
		universalChangeEntity.setProjectmanager(projectEntity.getProjectmanager());
		universalChangeEntity.setProjectmanagercode(projectEntity.getProjectmanagercode());
		universalChangeEntity.setChangereason(appointmentEntity.getChangereason());
		universalChangeEntity.setDeptname(getSessionUserBean().getDept().getFullname());
		universalChangeEntity.setDeptcode(getSessionUserBean().getDept().getCode());
		universalChangeEntity.setUsername(getSessionUserBean().getUser().getName());
		universalChangeEntity.setUsercode(getSessionUserBean().getUser().getCode());
		universalChangeEntity.setDocdate(new Date());
		universalChangeEntity.setVersion(appointmentEntity.getVersion());

		gpmProjectUniversalChangeService.insert(universalChangeEntity);
	}

    @Override
    protected void updateAfter(Map<String, Object> map) throws ServiceException {
        super.updateAfter(map);
        //更新变更模块的变更原因字段
        Map<String,Object> changeUpdateMap = new HashMap<String,Object>();
        changeUpdateMap.put(GpmProjectUniversalChangeEntity.FieldChangereason, map.get("changereason"));
        gpmProjectUniversalChangeService.updateByWhere(changeUpdateMap,"sourceid="+map.get("id") + " and sourcetype='"+ GpmProjectAppointmentEntity.tableName +"' and version="
                +map.get("version"));
    }

	/**
	 * @Description:    复制团队类型
	 * @Author:         mengmeng
	 * @Date:           2021/8/30 9:21
	 * @Version:        1.0
	 */
	private GpmProjectTeamTypeEntity copyTeamTypeDo(long appointId, GpmProjectTeamTypeEntity teamType) {
		GpmProjectTeamTypeEntity newTeamTypeDo = new GpmProjectTeamTypeEntity();
		BeanUtils.copyProperties(teamType, newTeamTypeDo);
		long[] arrayId = PrimaryKeyUtil.GeneIDsFromCache(teamType.getTableName(), 1);
		newTeamTypeDo.setCopysourceid(newTeamTypeDo.getId());
		newTeamTypeDo.setId(arrayId[0]);
		newTeamTypeDo.setAppointmentid(appointId);
		newTeamTypeDo.setSortCode(teamType.getSortcode());
		newTeamTypeDo.setDescription(ConvertUtil.convertToString(teamType.getId()));
		return newTeamTypeDo;
	}


	/**
	 * @Description:    上传任命书附件
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:58
	 * @Version:        1.0
	 */
	private void uploadAppointment(String sourceId, File file) {
		Map<String, Object> param = new HashMap<>();
		param.put("sourceType", "GpmProjectAppointmentGenerate");
		param.put("sourceId", sourceId);
		param.put("description", "SystemUpload");
		cboAttachmentService.executeUpload(param, file);
	}

	private void deleteAppointment(String sourceId) {
		cboAttachmentService.deleteByWhere(" sourcetype = 'GpmProjectAppointmentGenerate' and sourceid = " + sourceId);
	}

	/**
	 * @Description: 转pdf后下载模板文件
	 * @Author: mengmeng
	 * @Date: 2021/8/16 14:14
	 * @Version: 1.0
	 */
	@Override
	public Map<String, Object> executeDownload(Map<String, Object> paraMap) {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		try {
			// 附件对象
			StringBufferProxy sqlWhere = new StringBufferProxy();
			if (paraMap.containsKey("attachmentId")) {
				String attachmentId = ConvertUtil.convertToString(paraMap.get("attachmentId"));
				sqlWhere.appendLineSingle(" id={0}", attachmentId);
			} else {
				sqlWhere.appendLineSingle(" 1=1 ");
				if (paraMap.containsKey("sourcetype"))
					sqlWhere.appendLineSingle(" and sourcetype='{0}'",
							ConvertUtil.convertToString(paraMap.get("sourcetype")));
				if (paraMap.containsKey("sourceid"))
					sqlWhere.appendLineSingle(" and sourceid='{0}'",
							ConvertUtil.convertToString(paraMap.get("sourceid")));
			}
			Map<String, Object> queryMap = new HashMap<String, Object>();
			queryMap.put("whereSql", sqlWhere.toString());
			CboAttachmentEntity attachment = cboAttachmentService.getByte(queryMap);
			resultMap.put("attFileName", attachment.getDisplayname());
			// 存储配置
			CboAttachmentTypeEntity attachmentType = cboAttachmentTypeService
					.queryById(ConvertUtil.convertToString(attachment.getAttachmenttypeid()));
			if (attachmentType == null) {
				throw new ServiceException("没有设置正确的配置参数！");
			}
			if (attachmentType.getStoretype().equals(TapSystemConst.TapAttachmentStoreType.FTP)) {
				downloadFtp(resultMap, paraMap, attachment, attachmentType);
			}
		} catch (Exception e) {
			throw new ServiceException(e);
		}
		return resultMap;
	}
	/**
	 * @Description:    下载文件后转ftp
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:57
	 * @Version:        1.0
	 */
	private void downloadFtp(Map<String, Object> resultMap, Map<String, Object> paraMap, CboAttachmentEntity attachment,
			CboAttachmentTypeEntity attachmentType) {
		try {
			FTPProcessor ftpProcessor = null;
			ZipInputStream is = null;
			OutputStream os = null;
			String tempZipFilePath = null;
			String unZipFilePath = null;
			String tempZipDirectoryName = null;
			String uuid = UUID.randomUUID().toString();
			try {
				// 临时目录，用于解压缩文件
				tempZipDirectoryName = BaseUtil.getProjectPath() + "zip" + "\\" + uuid;
				File tempZipDirectory = new File(tempZipDirectoryName);
				if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
					tempZipDirectory.mkdirs();
				}
				// 打开FTP连接,下载并解压
				ftpProcessor = new FTPProcessor();
				ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
						Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
						attachmentType.getFtppwd());
				// Ftp文件路径
				String ftpFilePath = attachment.getSavepath() + attachment.getFilename();
				// Zip文件下载路径，下载Zip文件
				tempZipFilePath = tempZipDirectoryName + "\\" + attachment.getFilename();
				ftpProcessor.download(ftpFilePath, tempZipFilePath);
				String displayName = attachment.getDisplayname();
				if (attachmentType.getCompresszip() == 0)// 不压缩
				{
					resultMap.put("attFileName", displayName);
					resultMap.put("attInputStream", FileUtil.convertFileToBytes(tempZipFilePath));
				} else {
					// 解压
					ZipFile zipFile = new ZipFile(tempZipFilePath);
					zipFile.setFileNameCharset("GBK");
					if (zipFile.isEncrypted()) {
						zipFile.setPassword(attachment.getPwd());
					}
					List<FileHeader> fileHeaderList = zipFile.getFileHeaders();
					FileHeader fileHeader = fileHeaderList.get(0);
					if (fileHeader != null) {
						unZipFilePath = tempZipDirectoryName + "\\" + displayName;
						File unZipFile = new File(unZipFilePath);
						if (fileHeader.isDirectory()) {
							unZipFile.mkdirs();
						}
						is = zipFile.getInputStream(fileHeader);
						os = new FileOutputStream(unZipFile);
						int readLen = -1;
						byte[] buff = new byte[4096];
						while ((readLen = is.read(buff)) != -1) {
							os.write(buff, 0, readLen);
						}
						UnzipUtil.applyFileAttributes(fileHeader, unZipFile);
						String convertDisplayName = displayName.substring(0, displayName.indexOf(".")) + ".pdf";
						String destDirectory = tempZipDirectoryName + "\\" + convertDisplayName;
						GenerateAppointmentTemplateUtil.convertToPdf(unZipFilePath, destDirectory);
						resultMap.put("attFileName", convertDisplayName);
						resultMap.put("attInputStream", FileUtil.convertFileToBytes(destDirectory));
					}
				}
			} catch (Exception ex) {
				throw new ServiceException(ex);
			} finally {
				if (os != null) {
					os.close();
					os = null;
				}
				if (is != null) {
					is.close();
					is = null;
				}
				if (ftpProcessor != null) {
					ftpProcessor.close();
				}
				// 删除压缩文件
				FileUtil.deleteFile(tempZipFilePath);
				if (ParameterCache.getBooleanValue("CboAttchmentUnZipDelete", true)) {
					// 删除解压后的文件
					if (unZipFilePath != null) {
						FileUtil.deleteFile(unZipFilePath);
					}
					// 删除临时目录
					FileUtil.deleteDirectory(tempZipDirectoryName, true);
				} else {
					// edit by jichanghong 20180719
					// 电子工艺文件管理系统，根据工序拆分pdf文件要用unZipFilePath 与
					// tempZipDirectoryName
					resultMap.put("unZipFilePath", unZipFilePath);
					resultMap.put("tempZipDirectoryName", tempZipDirectoryName);
				}
			}
		} catch (Exception ex) {
			throw new ServiceException(ex);
		}
	}
	/**
	 * @Description: 转pdf发送邮件
	 * @Author: mengmeng
	 * @Date: 2021/8/16 14:15
	 * @Version: 1.0
	 */
	public void sendMessage(String appointId) {
		// 获取任命书对象
		Map<String, Object> appointDoMap = this.queryMapById(appointId);
		if (null == appointDoMap || appointDoMap.isEmpty()) {
			return;
		}
		String createOn = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldCreateon));

		// 判断是否是系统参数时间之前的任命书，不需要发送，为了处理历史数据
		if (judgeSendTime(createOn, null)) {
			return;
		}
		// 获取项目等级
		String projectCode = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldProjectcode));
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" {0} = '{1}' ", GpmProjectEntity.FieldProjectcode, projectCode);
		List<GpmProjectEntity> sdProjectEntities = gpmProjectService.queryByWhere(sql.toString());
		if (CollectionUtils.isEmpty(sdProjectEntities)) {
			return;
		}
		// 历史数据不发送任命
		if("1".equals(sdProjectEntities.get(0).getWhetherhistorydata())) {
			return;
		}
		String projectLevel = sdProjectEntities.get(0).getProjectlevel();
		// A、B发送邮件，C、D级不发送邮件
		if (StringUtil.isEmpty(projectLevel) || (!"0".equals(projectLevel) && !"1".equals(projectLevel))) {
			return;
		}
		// 判断是一次任命还是二次任命
		String sysPush = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldSyspush));
		String copyMailTo = "";

		List<GpmProjectTeamEntity> projectTeamDoList = gpmProjectTeamService.queryByAppointmentId(appointId);
		// 需要发送邮件的人员
		List<String> userCodeList = getStrings(appointDoMap, projectTeamDoList);
		if (CollectionUtils.isEmpty(userCodeList)) {
			return;
		}
		String sdMailToUserCode = ParameterCache.getValue("GpmMailToUserCode");
		Set<String> paramUserCode = StringUtil.isEmpty(sdMailToUserCode) ? null : Arrays.stream(sdMailToUserCode.split(",")).collect(Collectors.toSet());
		String userCodeStr = "";
		if (!CollectionUtils.isEmpty(paramUserCode)) {
			userCodeStr = userCodeList.stream().distinct().filter(item -> paramUserCode.contains(item)).map(item -> "'" + item + "'").collect(Collectors.joining(","));
		}
		else {
			userCodeStr = userCodeList.stream().distinct().map(item -> "'" + item + "'").collect(Collectors.joining(","));
		}
		if (StringUtil.isEmpty(userCodeStr)) {
			// 当发送邮件的人员为空时，默认发送给指定人员
			String defaultToUserCode = ParameterCache.getValue("GpmMailDefaultToUserCode");
			if (StringUtil.isEmpty(defaultToUserCode)) {
				return;
			}
			userCodeStr = defaultToUserCode;
		}
		List<CboUserEntity> cboUserDoList = cboUserService.queryByWhere(" code in (" + userCodeStr + ")");
		String mailTo = cboUserDoList.stream().map(CboUserEntity::getEmail).collect(Collectors.joining(","));
		// 获取任命书编号
		String appointNum = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldAppointmentnumber));
		if (appointNum.contains("[") && appointNum.contains("]")) {
			appointNum = appointNum.replace("[", "【").replace("]", "】");
		}
		String projectName = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldProjectname));
		String emailTitle = "";
		String fileName = "";
		if (!StringUtil.isEmpty(sysPush) && "1".equals(sysPush)) {
			// 一次任命
			copyMailTo = ParameterCache.getValue("GpmFirstAppointMail");
			emailTitle = "鼎信通用项目组任命" + appointNum + "-[" + projectName + "]" + "任命通知";
			fileName = projectName + "任命书";
		} else {
			// 二次任命
			copyMailTo = ParameterCache.getValue("GpmSecondAppointMail");
			emailTitle = "鼎信通用项目组任命" + appointNum + "-[" + projectName + "]" + "任命变更通知";
			fileName = projectName + "任命书-变更";
		}
		// 删除文件名中不允许包含的字符，防止报错
		String[] split = GpmSystemConst.generateAppointmentPrevent.split(",");
		for(String str : split) {
			fileName = fileName.replaceAll(str, "");
		}
		// 获取附件对象
		StringBufferProxy sqlWhere = new StringBufferProxy();
		sqlWhere.appendLineSingle(" sourcetype='{0}'", "GpmProjectAppointmentGenerate");
		sqlWhere.appendLineSingle(" and sourceid='{0}'", appointId);
		List<CboAttachmentEntity> attachmentEntityList = cboAttachmentService.queryByWhere(sqlWhere.toString());
		if (CollectionUtils.isEmpty(attachmentEntityList)) {
			return;
		}
		CboAttachmentEntity attachment = attachmentEntityList.get(0);
		// 存储配置
		CboAttachmentTypeEntity attachmentType = cboAttachmentTypeService
				.queryById(ConvertUtil.convertToString(attachment.getAttachmenttypeid()));
		String mailAttachmentPath = null;
		String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
		String tempZipDirectoryName = System.getProperty("user.dir").replace("bin", "webapps") + "/mailZip/"
				+ currentNanoTime + "/";
		try {
			// 转成邮件发送消息
			MailMessageEntity mailMessageEntity = new MailMessageEntity();
			mailMessageEntity.setContent("");
			mailMessageEntity.setTitle(emailTitle);
			mailMessageEntity.setMailTo(mailTo);
			// 邮件附件
			mailAttachmentPath = downloadFtpForMail(attachment, attachmentType, tempZipDirectoryName, fileName);
			List<File> fileList = new ArrayList<>();
			File file = new File(mailAttachmentPath);
			fileList.add(file);
			mailMessageEntity.setAttachments(fileList);
			// 发送消息

			int indexOf = mailAttachmentPath.lastIndexOf("\\");
			String temp = mailAttachmentPath.substring(indexOf + 1);
			indexOf = temp.lastIndexOf("/");
			if (indexOf > -1) {
				temp = temp.substring(indexOf + 1);
			}
			sendMail(mailMessageEntity, file, copyMailTo, temp);
		} finally {
			FileUtil.deleteDirectory(tempZipDirectoryName, true);
		}
	}
	/**
	 * @Description:    下载任命书并放在邮件中的附件中
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:55
	 * @Version:        1.0
	 */
	private String downloadFtpForMail(CboAttachmentEntity attachment, CboAttachmentTypeEntity attachmentType, String directory, String fileName) {
		try {
			FTPProcessor ftpProcessor = null;
			ZipInputStream is = null;
			OutputStream os = null;
			String tempZipFilePath = null;
			String unZipFilePath = null;
			String destDirectory = null;
			try {
				// 临时目录，用于解压缩文件
				File tempZipDirectory = new File(directory);
				if (!tempZipDirectory.exists() && !tempZipDirectory.isDirectory()) {
					tempZipDirectory.mkdirs();
				}
				// 打开FTP连接,下载并解压
				ftpProcessor = new FTPProcessor();
				ftpProcessor.connect(attachmentType.getFtppath(), attachmentType.getFtpserver(),
						Integer.parseInt(attachmentType.getFtpport()), attachmentType.getFtpuser(),
						attachmentType.getFtppwd());
				// Ftp文件路径
				String ftpFilePath = attachment.getSavepath() + attachment.getFilename();
				// Zip文件下载路径，下载Zip文件
				tempZipFilePath = directory + attachment.getFilename();
				ftpProcessor.download(ftpFilePath, tempZipFilePath);
				String displayName = attachment.getDisplayname();
				if (attachmentType.getCompresszip() == 0)// 不压缩
				{
					unZipFilePath = directory + attachment.getDisplayname();
				} else {
					// 解压
					ZipFile zipFile = new ZipFile(tempZipFilePath);
					zipFile.setFileNameCharset("GBK");
					if (zipFile.isEncrypted()) {
						zipFile.setPassword(attachment.getPwd());
					}
					List<FileHeader> fileHeaderList = zipFile.getFileHeaders();
					FileHeader fileHeader = fileHeaderList.get(0);
					if (fileHeader != null) {
						unZipFilePath = directory + attachment.getDisplayname();
						File unZipFile = new File(unZipFilePath);
						if (fileHeader.isDirectory()) {
							unZipFile.mkdirs();
						}
						is = zipFile.getInputStream(fileHeader);
						os = new FileOutputStream(unZipFile);
						int readLen = -1;
						byte[] buff = new byte[4096];
						while ((readLen = is.read(buff)) != -1) {
							os.write(buff, 0, readLen);
						}
						UnzipUtil.applyFileAttributes(fileHeader, unZipFile);
						if (!attachment.getFiletype().equals(".PDF")) {
							String convertDisplayName = fileName + ".pdf";
							destDirectory = directory + convertDisplayName;
							GenerateAppointmentTemplateUtil.convertToPdf(unZipFilePath, destDirectory);
						}
					}
				}
			} catch (Exception ex) {
				throw new ServiceException(ex);
			} finally {
				if (os != null) {
					os.close();
					os = null;
				}
				if (is != null) {
					is.close();
					is = null;
				}
				if (ftpProcessor != null) {
					ftpProcessor.close();
				}
				FileUtil.deleteFile(tempZipFilePath);
			}
			return attachment.getFiletype().equals(".PDF") ? unZipFilePath : destDirectory;
		} catch (Exception ex) {
			throw new ServiceException(ex);
		}
	}
	/**
	 * @Description:    填写邮件所需必要信息并发送邮件
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:56
	 * @Version:        1.0
	 */
	private void sendMail(MailMessageEntity mailMessageEntity, File toFile, String copyMailTo, String toFileName) {
		String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
		String imagePath = System.getProperty("user.dir").replace("bin", "webapps") + "/pdfImage/" + currentNanoTime + "/";
		String imagePrefix = "pdfimage";
		String mailTo = mailMessageEntity.getMailTo();
		/**
		 * 邮箱服务器
		 */
		String mailServer = ParameterCache.getValue("CboMailServer");
		/**
		 * 发送人邮箱账号
		 */
		String mailSendUserName = ParameterCache.getValue("CboMailSendUserName");
		/**
		 * 发送人邮箱密码
		 */
		String mailSendPassword = ParameterCache.getValue("CboMailSendPassword");
		try {
			MimeMessage mimeMessage = setMailServer(mailServer, mailSendUserName, mailSendPassword);
			// 发件人
			String sendername = javax.mail.internet.MimeUtility.encodeText(mailSendUserName);
			mimeMessage.setFrom(new InternetAddress(sendername + "<" + mailSendUserName + ">"));
			// 收件人
			InternetAddress[] arrayRecipients = InternetAddress.parse(mailTo);
			InternetAddress[] copyRecipients = InternetAddress.parse(copyMailTo);
			mimeMessage.setRecipients(Message.RecipientType.TO, arrayRecipients);
			mimeMessage.setRecipients(Message.RecipientType.CC, copyRecipients);
			// 邮件的标题
			String title = mailMessageEntity.getTitle();
			mimeMessage.setSubject(MimeUtility.encodeText(title, "UTF-8", "B"));
			// 邮件图片
			MimeMultipart mimeMultipart = insertImage(toFile, imagePath, imagePrefix);
			// 邮件附件
			MimeMultipart attachPart = new MimeMultipart();
			MimeBodyPart image = new MimeBodyPart();
			image.setContent(mimeMultipart);
			MimeBodyPart attach = new MimeBodyPart();
			DataHandler dataHandler = new DataHandler(new FileDataSource(toFile));
			attach.setDataHandler(dataHandler);
			String property = System.getProperties().getProperty("file.separator");
			// 过滤掉开头的斜线或者下划线
			toFileName = dealFileName(toFileName, property);
			String resultFileName = MimeUtility.encodeText(toFileName, "UTF-8", "B");
			resultFileName = resultFileName.replace("\\r","").replace("\\n","");
			attach.setFileName(resultFileName);
			attachPart.addBodyPart(attach);
			attachPart.addBodyPart(image);
			attachPart.setSubType("mixed");
			// 创建容器描述数据关系
			mimeMessage.setContent(attachPart);
			mimeMessage.saveChanges();
			// 发送邮件
			Transport.send(mimeMessage);
		}
		catch (SendFailedException s) {
			// 判断当前失败信息，如果为地址错误，则过滤无效地址后重发
			if (INVALID_ADDRESS_MESSAGE.equals(s.getMessage())) {
				Address[] addresses = s.getInvalidAddresses();
				List<String> addressList = new ArrayList<>();

				List<String> recipientList = Arrays.stream(mailTo.split(",")).collect(Collectors.toList());
				List<String> ccList = Arrays.stream(copyMailTo.split(",")).collect(Collectors.toList());
				for (Address address : addresses) {
					InternetAddress internetAddress = (InternetAddress) address;
					String invalidAddress = internetAddress.getAddress();
                    recipientList.remove(invalidAddress);
                    ccList.remove(invalidAddress);
					addressList.add(invalidAddress);
				}
				logger.info("存在不可用邮箱地址:{},过滤后重新发送邮件...", JSON.toJSONString(addressList));

				if (CollectionUtils.isEmpty(recipientList)) {
					logger.info("收件人不存在有效的邮箱地址,已配置但无效的邮箱地址：{}", JSON.toJSONString(recipientList));
					throw new ServiceException("不存在有效的邮箱地址，已配置但无效的邮箱地址：" + JSON.toJSONString(addressList));
				}
				if (CollectionUtils.isEmpty(ccList)) {
					logger.info("抄送人不存在有效的邮箱地址,已配置但无效的邮箱地址：{}", JSON.toJSONString(ccList));
					throw new ServiceException("不存在有效的邮箱地址，已配置但无效的邮箱地址：" + JSON.toJSONString(addressList));
				}
				// 重新发送
				mailMessageEntity.setMailTo(recipientList.stream().collect(Collectors.joining(",")));
				copyMailTo = ccList.stream().collect(Collectors.joining(","));
				sendMail1(mailMessageEntity, toFile, copyMailTo, toFileName);
			} else {
				throw new ServiceException(s);
			}
		}
		catch (Exception ex) {
			throw new BusinessException(ex);
		} finally {
			FileUtil.deleteDirectory(imagePath, true);
		}
	}
	/**
	 * @Description:    在发送给失效的邮箱时，需要重新发送邮件，重写发送邮件的方法，避免进入递归死循环
	 * @Author:         mengmeng
	 * @Date:           2021/10/19 10:52
	 * @Version:        1.0
	 */
	private void sendMail1(MailMessageEntity mailMessageEntity, File toFile, String copyMailTo, String toFileName) {
		String currentNanoTime = ConvertUtil.convertToString(System.nanoTime());
		String imagePath = System.getProperty("user.dir").replace("bin", "webapps") + "/pdfImage/" + currentNanoTime + "/";
		String imagePrefix = "pdfimage";
		String mailTo = mailMessageEntity.getMailTo();
		/**
		 * 邮箱服务器
		 */
		String mailServer = ParameterCache.getValue("CboMailServer");
		/**
		 * 发送人邮箱账号
		 */
		String mailSendUserName = ParameterCache.getValue("CboMailSendUserName");
		/**
		 * 发送人邮箱密码
		 */
		String mailSendPassword = ParameterCache.getValue("CboMailSendPassword");
		try {
			MimeMessage mimeMessage = setMailServer(mailServer, mailSendUserName, mailSendPassword);
			// 发件人
			String sendername = javax.mail.internet.MimeUtility.encodeText(mailSendUserName);
			mimeMessage.setFrom(new InternetAddress(sendername + "<" + mailSendUserName + ">"));
			// 收件人
			InternetAddress[] arrayRecipients = InternetAddress.parse(mailTo);
			InternetAddress[] copyRecipients = InternetAddress.parse(copyMailTo);
			mimeMessage.setRecipients(Message.RecipientType.TO, arrayRecipients);
			mimeMessage.setRecipients(Message.RecipientType.CC, copyRecipients);
			// 邮件的标题
			String title = mailMessageEntity.getTitle();
			mimeMessage.setSubject(MimeUtility.encodeText(title, "UTF-8", "B"));
			// 邮件图片
			MimeMultipart mimeMultipart = insertImage(toFile, imagePath, imagePrefix);
			// 邮件附件
			MimeMultipart attachPart = new MimeMultipart();
			MimeBodyPart image = new MimeBodyPart();
			image.setContent(mimeMultipart);
			MimeBodyPart attach = new MimeBodyPart();
			DataHandler dataHandler = new DataHandler(new FileDataSource(toFile));
			attach.setDataHandler(dataHandler);
			String property = System.getProperties().getProperty("file.separator");
			// 过滤掉开头的斜线或者下划线
			toFileName = dealFileName(toFileName, property);
			String resultFileName = MimeUtility.encodeText(toFileName, "UTF-8", "B");
			resultFileName = resultFileName.replace("\\r","").replace("\\n","");
			attach.setFileName(resultFileName);
			attachPart.addBodyPart(attach);
			attachPart.addBodyPart(image);
			attachPart.setSubType("mixed");
			// 创建容器描述数据关系
			mimeMessage.setContent(attachPart);
			mimeMessage.saveChanges();
			// 发送邮件
			Transport.send(mimeMessage);
		} catch (Exception ex) {
			throw new BusinessException(ex);
		} finally {
			FileUtil.deleteDirectory(imagePath, true);
		}
	}

	private String dealFileName(String fileName, String property) {
		if (fileName.startsWith(property)) {
			fileName = fileName.substring(1);
		}
		else {
			return fileName;
		}
		return dealFileName(fileName, property);
	}

	/**
	 * @Description:    向邮件内容中填写图片
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 9:57
	 * @Version:        1.0
	 */
	private MimeMultipart insertImage(File pdf, String imagePath, String imageNamePrefix) throws MessagingException, IOException {
		MimeMultipart mimeMultipart = new MimeMultipart();
		int total = PdfToImageUtil.toImageFromByte(imagePath, imageNamePrefix, FileUtil.convertFileToBytes(pdf), true);
		MimeBodyPart image = new MimeBodyPart();
		//图片需要经过数据处理..DataHandler：数据处理
		image.setDataHandler(new DataHandler(new FileDataSource(imagePath + imageNamePrefix + ".png")));//在我们的body中放入这个处理的图片数据
		image.setContentID(imageNamePrefix + ".png");//给图片设置一个ID方便调用
		mimeMultipart.addBodyPart(image);
		MimeBodyPart mailContent = new MimeBodyPart();
		String content = "<hr color='#b5c4df' style='width:200px;float:left;'><br>\n" +
				"<span style='color: rgb(128, 128, 128);line-height: 18px;font-family: Verdana;white-space: nowrap;font-size: 12px;'>&nbsp;&nbsp;鼎信通讯 经营管理部</span><br>\n" +
				"<span style='font-family: Calibri;color: rgb(128, 128, 128);white-space: nowrap;line-height: normal;font-size: 12px;'>&nbsp;&nbsp;=========================================</span><br>\n" +
				"<span style='color: rgb(128, 128, 128);line-height: 18px;font-family: Verdana;white-space: nowrap;font-size: 12px;'>&nbsp;&nbsp;青岛市高新区华贯路858号 鼎信科技产业园</span>";
		mailContent.setContent("<img src='cid:" + imageNamePrefix + ".png'><br>" + content, "text/html;charset=UTF-8");
		mimeMultipart.addBodyPart(mailContent);
		mimeMultipart.setSubType("related");
		return mimeMultipart;
	}

	/**
	 * @Description:    设置邮箱服务
	 * @Author:         mengmeng
	 * @Date:           2021/10/19 10:46
	 * @Version:        1.0
	 */
	private MimeMessage setMailServer(String mailServer, String mailSendUserName, String mailSendPassword) throws GeneralSecurityException {
		// 邮件服务器
		Properties prop = System.getProperties();
		prop.setProperty("mail.host", mailServer);
		prop.setProperty("mail.transport.protocol", "smtp");
		prop.setProperty("mail.smtp.auth", "true");
		prop.setProperty("mail.smtp.port", "465");
		prop.setProperty("mail.smtp.ssl.enable", "true");
		System.getProperties().setProperty("mail.mime.splitlongparameters", "false");
		// 设置SSL加密
		MailSSLSocketFactory sf = new MailSSLSocketFactory();
		sf.setTrustAllHosts(true);
		prop.put("mail.smtp.ssl.socketFactory", sf);
		// 创建会话对象
		Authenticator authenticator = new Authenticator() {
			@Override
			public PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(mailSendUserName, mailSendPassword);
			}
		};
		Session session = Session.getInstance(prop, authenticator);
		session.setDebug(true);
		// MimeMessage对象
		return new MimeMessage(session);
	}

	/**
	 * @Description:    返回true不需要发送邮件
	 * @Author:         mengmeng
	 * @Date:           2021/8/24 15:55
	 * @Version:        1.0
	 */
	public boolean judgeSendTime(String createOnStr, Date createOnDate) {
		boolean strEmpty = StringUtil.isEmpty(createOnStr);
		boolean dateEmpty = createOnDate == null;
		if (strEmpty && dateEmpty) {
			return false;
		}
		String sendEmailTime = ParameterCache.getValue("sendEmailTime");
		Date parse = null;
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date createOnTime = null;
		try {
			parse = simpleDateFormat.parse(sendEmailTime);
			if (!strEmpty) {
				createOnTime = simpleDateFormat.parse(createOnStr);
				return createOnTime.before(parse);
			}
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return createOnDate.before(parse);
	}

	/**
	 * @Description: 获取团队成员
	 * @Author: mengmeng
	 * @Date: 2021/8/17 20:35
	 * @Version: 1.0
	 */
	private List<String> getStrings(Map<String, Object> appointDoMap, List<GpmProjectTeamEntity> projectTeamDoList) {
		List<String> userCodeList = projectTeamDoList.stream().map(GpmProjectTeamEntity::getUsercode).collect(Collectors.toList());
		userCodeList = userCodeList.stream().filter(item -> !StringUtil.isEmpty(item)).collect(Collectors.toList());
		String projectManagerCode = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldProjectmanagercode));
		userCodeList.add(projectManagerCode);
		String sponsorCode = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldSponsorcode));
		userCodeList.add(sponsorCode);
		String signerCode = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldSignercode));
		userCodeList.add(signerCode);
		String adviserCode = ConvertUtil.convertToString(appointDoMap.get(GpmProjectAppointmentEntity.FieldAdvisercode));
		userCodeList.add(adviserCode);
		return userCodeList;
	}

	@Override protected void deleteBefore(String whereSql) {
		super.deleteBefore(whereSql);
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle(" appointmentid in (select id from {0} where {1} )", GpmProjectAppointmentEntity.tableName,whereSql);
		gpmProjectTeamService.deleteByWhere(sql.toString());
		gpmProjectTeamTypeService.deleteByWhere(sql.toString());
		sql.clear();
		sql.appendSingle(" delete from {2} where sourceid in (select id from {0} where {1} ) and sourcetype= '{0}' ", GpmProjectAppointmentEntity.tableName,whereSql, GpmProjectUniversalChangeEntity.tableName);
		gpmProjectUniversalChangeService.deleteExecute(sql.toString());
	}

	@Override
	protected void afterApprove(TapEntity billEntity, CboApprovalNodeInsEntity nodeIns, CboApprovalNodeEntity node,
			SessionUserBean sessionUserBean) {
		GpmProjectAppointmentEntity gpmProjectAppointmentEntity = (GpmProjectAppointmentEntity)billEntity;
		//审批通过后，下发任务
		if(gpmProjectAppointmentEntity.getState() == 9) {
			String projectcode = gpmProjectAppointmentEntity.getProjectcode();
			StringBufferProxy sql = new StringBufferProxy();
			sql.appendSingle("projectcode = '{0}'", projectcode);
			List<GpmProjectEntity> sdProjectEntities = gpmProjectService.queryByWhere(sql.toString());
			if (CollectionUtils.isEmpty(sdProjectEntities)) {
				return;
			}
			GpmProjectEntity projectEntity = sdProjectEntities.get(0);
			StringBufferProxy content = new StringBufferProxy();
			sql.clear();
			Map<String, Object> messageAppmap = new HashMap<String, Object>();
			String projectname = projectEntity.getProjectname();
			projectname = projectname.endsWith("项目") ? projectname : projectname + "项目";
			content.appendSingle("您提交的【{0}】任命书已审批通过，任命书编号为{1}，请于7天内组织完成项目策划。",
					projectname, gpmProjectAppointmentEntity.getAppointmentnumber());
//			messageAppmap.put("usercode", projectEntity.getProjectmanagercode());
			messageAppmap.put("receivercode", projectEntity.getProjectmanagercode());
			messageAppmap.put("receivername", projectEntity.getProjectmanager());
			messageAppmap.put("content", content.toString());
			messageAppmap.put("extendfield1", "任命书审批通知");
			messageAppmap.put("sendtype", "0");
			messageAppmap.put("sourcetype", GpmProjectAppointmentEntity.tableName);
			messageAppmap.put("sourceid", projectEntity.getId());
			messageAppmap.put("messagetype", MisSystemConst.MobileMessageType.TASK_TYPE);
			sendMessageService.sendAppMessage(messageAppmap,ConvertUtil.convertToString(nodeIns.getId()));
//			cboMessageAppService.insertMap(messageAppmap);
			// 系统通知消息
			Map<String, Object> messageSysAppmap = new HashMap<String, Object>();
			messageSysAppmap.put("receivercode", projectEntity.getProjectmanagercode());
			messageSysAppmap.put("receivername",projectEntity.getProjectmanager());
			messageSysAppmap.put("content", content.toString());
			messageSysAppmap.put("subject", "任命书审批通知");
			messageSysAppmap.put("ishtm", 0);
			messageSysAppmap.put("sourcetype", GpmProjectAppointmentEntity.tableName);
			messageSysAppmap.put("sourceid", projectEntity.getId());
			messageSysAppmap.put("messagetype", MisSystemConst.MobileMessageType.TASK_TYPE);
			sendMessageService.sendSysMessage(messageSysAppmap,ConvertUtil.convertToString(nodeIns.getId()));
//			cboMessageSysService.insertMap(messageSysAppmap);
		}
		this.updateUniversalChange(billEntity, GpmProjectAppointmentEntity.tableName);
		super.afterApprove(billEntity, nodeIns, node, sessionUserBean);
	}

	@Override
	protected void afterDelApprove(TapEntity entity, SessionUserBean sessionUserBean) {
		//取消审批删除通用变更表信息
		gpmProjectUniversalChangeService.deleteByWhere("sourceid = " + entity.getValue("id") +
				" and sourcetype = '" + GpmProjectAppointmentEntity.tableName + "' and version = "+entity.getValue("version"));
		super.afterDelApprove(entity, sessionUserBean);
	}

	/**
	 * @description: 变更退回修改节F点审批通过
	 * @param id
	 * @return
	 * @author: wangxinhua
	 * @date: 2021/12/13 14:39
	 * @modify:
	 */
	@Transactional(rollbackFor = Exception.class)
	public void changeEditNodePass(String id) {
		GpmProjectAppointmentEntity appointmentEntity = this.queryById(id);
		//删除上次的basechangelog
		baseChangeLogService.deleteByWhere(" topsourcetype='"+appointmentEntity.getTableName()+"'"
				+ " and topsourceid='"+appointmentEntity.getId()+"'"
				+ " and version="+appointmentEntity.getVersion());
		try {
			Map<String, Object> changeData = this.getBaseChangeEntity(appointmentEntity.convertToMap());
			this.saveBaseChangelog(changeData, true);
		}catch (Exception e) {
			throw new ServiceException("存储变更信息失败！");
		}
	}
	/**
	 * @author houyuhang
	 * @Description 首页信息概览任命待办
	 * @Date 2021/12/21
	 * @return Map<String,Object>
	 **/
	public Map<String,Object> queryBacklogAppointment(Map<String,Object> paraMap) {
		Map<String, Object> backlogAppointmentResult = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 项目状态为进行中的数据权限内项目
		sql.appendSingle(" GPMPROJECT.projectstate in ({0}) and GPMPROJECT.enabled = 1 and {1} ", GpmSystemConst.ProjectOngoingState,
				gpmProjectService.whereExistsSqlForIndex(GpmProjectEntity.tableName, GpmProjectEntity.FieldId,
						ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		// 任命待办拼接字符串，项目立项完成时间不为空，但项目任命不存在或者只存在一条未提交审批的任命
		sql.appendSingle("AND GPMPROJECT.FINISHDATE IS NOT NULL AND (gpmPROJECTAPPOINTMENT.ID IS NULL OR " +
				"(gpmPROJECTAPPOINTMENT.STATE = 0 AND gpmPROJECTAPPOINTMENT.VERSION = 1))");
		Map<String,Object> dataMap = new HashMap<>();
		dataMap.put("whereSql",sql.toString());
		int countBacklogAppointment = gpmProjectService.getCount(dataMap,"queryAppointmentOverdue");
		backlogAppointmentResult.put("code", "backlogAppointmentNum");
		backlogAppointmentResult.put("name", "任命待办");
		backlogAppointmentResult.put("iconImg", "/static/images/paojectManager/backlogappointment.png");
		backlogAppointmentResult.put("value", countBacklogAppointment);
		return backlogAppointmentResult;
	}
	/**
	 * @author houyuhang
	 * @Description 首页信息概览任命超期
	 * @Date 2021/11/29
	 * @return Map<String,Object>
	 **/
	public Map<String,Object> queryOverdueAppointment(Map<String,Object> paraMap){
		Map<String, Object> overdueAppointmentResult = new HashMap<>();
		StringBufferProxy sql = new StringBufferProxy();
		// 项目状态为进行中的数据权限内项目
		sql.appendSingle(" GPMPROJECT.projectstate in ({0}) and GPMPROJECT.enabled = 1 " +
						" and {1} ", GpmSystemConst.ProjectOngoingState,
				gpmProjectService.whereExistsSqlForIndex(GpmProjectEntity.tableName, GpmProjectEntity.FieldId
						, ConvertUtil.convertToString(paraMap.get("dataPermissionFlag"))));
		// 任命超期拼接字符串，项目立项完成时间不为空，但项目任命不存在或者只存在一条未审批完成的任命
		sql.appendSingle("AND GPMPROJECT.FINISHDATE IS NOT NULL AND (gpmPROJECTAPPOINTMENT.ID IS NULL OR " +
				"(gpmPROJECTAPPOINTMENT.STATE < 9 AND gpmPROJECTAPPOINTMENT.VERSION = 1))");
		// 获取4天之前的日期
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		String overdueAppointmentTime = GpmSystemConst.overdueAppointmentTime;
		int time = Integer.parseInt(overdueAppointmentTime) * (-1);
		calendar.add(Calendar.DATE,time);
		Date overdueDate = calendar.getTime();
		String overdueTime = DateUtil.dateToString(overdueDate,"yyyy-MM-dd");
		Map<String,Object> dataMap = new HashMap<>();
		dataMap.put("whereSql",sql.toString());
		dataMap.put("overdue",1);
		dataMap.put("overduetime",overdueTime);
		int countAppointment = gpmProjectService.getCount(dataMap,"queryAppointmentOverdue");
		overdueAppointmentResult.put("code", "overdueAppointmentNum");
		overdueAppointmentResult.put("name", "超期任命");
		overdueAppointmentResult.put("iconImg", "/static/images/paojectManager/overdueAppointment.png");
		overdueAppointmentResult.put("value", countAppointment);
		return overdueAppointmentResult;
	}
	/**
	 * @Description:    生成任命书
	 * @Author:         houyuhang
	 * @Date:           2021/12/29
	 * @Version:        1.0
	 */
	public void generateAppointment(GpmProjectAppointmentEntity gpmProjectAppointmentEntity, GpmProjectEntity gpmProjectEntity) throws Exception {
		Map<String, Object> param = new HashMap<>();
		param.put("appointmentnumber", gpmProjectAppointmentEntity.getAppointmentnumber());
		String projectName = gpmProjectAppointmentEntity.getProjectname();
		param.put("projectname", getProjectName(projectName));
		param.put("appointmentdescription", gpmProjectAppointmentEntity.getAppointmentdescription());
		param.put("signercode", gpmProjectAppointmentEntity.getSignername());
		param.put("appointmentid", gpmProjectAppointmentEntity.getId());
		// 构造sponsor owner projectmanager列表
		List<Map<String, Object>> sslist = new ArrayList<>();
		generateRole(sslist, "Sponsor", gpmProjectEntity.getSponsor(), gpmProjectEntity.getSponsorcode());
		generateRole(sslist, "Owner", gpmProjectEntity.getOwner(), gpmProjectEntity.getOwnercode());
		generateRole(sslist, "PM", gpmProjectEntity.getProjectmanager(), gpmProjectEntity.getProjectmanagercode());
		String adviser = gpmProjectAppointmentEntity.getAdviser();
		String adviserCode = gpmProjectAppointmentEntity.getAdvisercode();
		if (!StringUtil.isEmpty(adviser) && !StringUtil.isEmpty(adviserCode)) {
			generateRole(sslist, "顾问", adviser, adviserCode);
		}
		param.put("sslist", sslist);
		// 构造核心组
		List<Map<String, Object>> tablelist = new ArrayList<>();
		generateProjectTeam(gpmProjectAppointmentEntity.getId(), tablelist);
		param.put("tablelist", tablelist);
		// 生成任命书
		generateAppointment(param);
	}
	/**
	 * @Description:    给项目名称后面追加 ‘项目’ 两个字
	 * @Author:         houyuhang
	 * @Date:           2021/12/29
	 * @Version:        1.0
	 */
	private String getProjectName(String projectName) {
		if (StringUtil.isEmpty(projectName)) {
			return "";
		}
		return projectName.endsWith("项目") ? projectName : projectName + "项目";
	}
	/**
	 * @Description:    构造角色
	 * @Author:         houyuhang
	 * @Date:           2021/12/29
	 * @Version:        1.0
	 */
	private void generateRole(List<Map<String, Object>> sslist, String role, String name, String code) {
		Map<String, Object> sponsor = new HashMap<>();
		sponsor.put("ss", name);
		sponsor.put("ssc", code);
		sponsor.put("ssn", role);
		sslist.add(sponsor);
	}
	/**
	 * @Description:    构造项目组
	 * @Author:         mengmeng
	 * @Date:           2021/8/19 10:06
	 * @Version:        1.0
	 */
	private void generateProjectTeam(Long appointId, List<Map<String, Object>> tablelist) {
		List<Map<String, Object>> maps = gpmProjectTeamService.queryTeamAndTeamType(ConvertUtil.convertToString(appointId));
		gpmProjectTeamService.setDispFields(maps);
		StringBufferProxy sql = new StringBufferProxy();
		sql.appendSingle("{0} = '{1}' order by sortcode asc, createon asc", GpmProjectTeamTypeEntity.FieldAppointmentid,
				appointId);
		tablelist.addAll(gpmProjectTeamTypeService.queryMapByWhere(sql.toString()));
		Map<String, List<Map<String, Object>>> teamTypeIdToTeamMap = maps.stream().collect(Collectors.groupingBy(item ->
				ConvertUtil.convertToString(item.get(GpmProjectTeamEntity.FieldTeamid))));
		if (!CollectionUtils.isEmpty(tablelist)) {
			for (Map<String, Object> map : tablelist) {
				map.put("name", map.get(GpmProjectTeamTypeEntity.FieldTeamname));
				String key = ConvertUtil.convertToString(map.get(GpmProjectTeamTypeEntity.FieldId));
				List<Map<String, Object>> temp = teamTypeIdToTeamMap.computeIfAbsent(key, k -> new ArrayList<>());
				map.put("table", temp);
			}
		}
	}
	/**
	 * @Description:    判断该部门是否发送任命
	 * @Author:         houyuhang
	 * @Date:           2022/01/14
	 * @Version:        1.0
	 */
	public Boolean queryAppointmentSendByDept(String deptcommoncode1) {
		String appointmentSendExcept = "," + GpmSystemConst.AppointmentSendExcept + ",";
		String deptcommoncode1Temp = "," + deptcommoncode1 + ",";
        return !appointmentSendExcept.contains(deptcommoncode1Temp);
    }
}
